package services

import (
	"encoding/json"
	"errors"
	"fmt"
	"github.com/beego/beego/v2/client/orm"
	"github.com/beego/beego/v2/server/web/context"
	"github.com/silenceper/wechat"
	"github.com/silenceper/wechat/js"
	"github.com/silenceper/wechat/menu"
	"github.com/silenceper/wechat/message"
	"github.com/silenceper/wechat/oauth"
	"github.com/silenceper/wechat/util"
	"net/http"
	"time"
	"weiboxs.com/new_h_glasses/models"
	"weiboxs.com/new_h_glasses/utils"
)

const (
	getUserList         = "https://api.weixin.qq.com/cgi-bin/user/get?access_token=%s&next_openid=%s"
	getUserInfo         = "https://api.weixin.qq.com/cgi-bin/user/info?access_token=%s&openid=%s&lang=zh_CN"
	getBatchgetUserInfo = "https://api.weixin.qq.com/cgi-bin/user/info/batchget?access_token=%s"
)

//微信接口
type WechatApiService struct {
	Config map[string]string
	Depid  int64
}

//初始化
func (s *WechatApiService) NewWechatApiService() *wechat.Wechat {
	modes := models.WechatSetings{}
	setings := modes.GetSetings(true)
	config := &wechat.Config{}
	if _, ok := setings["AppID"]; ok {
		config.AppID = setings["AppID"]
	}
	if _, ok := setings["AppSecret"]; ok {
		config.AppSecret = setings["AppSecret"]
	}
	if _, ok := setings["Token"]; ok {
		config.Token = setings["Token"]
	}
	if _, ok := setings["EncodingAESKey"]; ok {
		config.EncodingAESKey = setings["EncodingAESKey"]
	}
	s.Config = setings //设置配置信息传递

	config.Cache = &utils.OrmCache{}
	wc := wechat.NewWechat(config)
	return wc
}

//接口消息入口
func (s *WechatApiService) WechatIndex(ctx *context.Context) {
	wc := s.NewWechatApiService()
	server := wc.GetServer(ctx.Request, ctx.ResponseWriter)
	//设置接收消息的处理方法
	server.SetMessageHandler(func(msg message.MixMessage) *message.Reply {
		return s.receiveMessage(msg)
	})
	server.SetDebug(true)
	//处理消息接收以及回复
	err := server.Serve()
	if err != nil {
		utils.LogInfo(err.Error())
		return
	}
	//发送回复的消息
	server.Send()
}

//接收普通事件
func (s *WechatApiService) receiveMessage(value message.MixMessage) *message.Reply {
	msg := &WechatMessageService{message: value, config: s.Config, Depid: s.Depid}
	switch value.MsgType {
	case message.MsgTypeText: //文本消息
		return msg.MsgTypeText()
	case message.MsgTypeImage: //图片消息
		return msg.MsgTypeImage()
	case message.MsgTypeVoice: //语音消息
		return msg.MsgTypeVoice()
	case message.MsgTypeVideo: //视频消息
		return msg.MsgTypeVideo()
	case message.MsgTypeShortVideo: //小视频消息
		return msg.MsgTypeShortVideo()
	case message.MsgTypeLocation: //地理位置消息
		return msg.MsgTypeLocation()
	case message.MsgTypeLink: //链接消息
		return msg.MsgTypeLink()
	case message.MsgTypeEvent: //事件推送消息
		return s.eventMessage(value, msg)
	}
	return nil
}

//接收推送事件
func (s *WechatApiService) eventMessage(value message.MixMessage, msgObject *WechatMessageService) *message.Reply {

	switch value.Event {
	case message.EventSubscribe:                                  //EventSubscribe 订阅
		go s.handleEventSubscribe(msgObject.message.FromUserName) //写入关注信息
		return msgObject.EventSubscribe()
	case message.EventUnsubscribe: //取消订阅
		return msgObject.EventUnsubscribe()
	case message.EventScan: //用户已经关注公众号，则微信会将带场景值扫描事件推送给开发者
		return msgObject.EventScan()
	case message.EventLocation: // 上报地理位置事件
		return msgObject.EventLocation()
	case message.EventClick: // 点击菜单拉取消息时的事件推送
		return msgObject.EventClick()
	case message.EventView: // 点击菜单跳转链接时的事件推送
		return msgObject.EventView()
	case message.EventScancodePush: // 扫码推事件的事件推送
		return msgObject.EventScancodePush()
	case message.EventScancodeWaitmsg: // 扫码推事件且弹出“消息接收中”提示框的事件推送
		return msgObject.EventScancodeWaitmsg()
	case message.EventPicSysphoto: // 弹出系统拍照发图的事件推送
		return msgObject.EventPicSysphoto()
	case message.EventPicPhotoOrAlbum: // 弹出拍照或者相册发图的事件推送
		return msgObject.EventPicPhotoOrAlbum()
	case message.EventPicWeixin: // 弹出微信相册发图器的事件推送
		return msgObject.EventPicWeixin()
	case message.EventLocationSelect: // 弹出地理位置选择器的事件推送
		return msgObject.EventLocationSelect()
	}
	return nil
}

//写入关注信息
func (s *WechatApiService) handleEventSubscribe(fromUserName message.CDATA) error {

	userinfo, err := s.GetUserInfo(fromUserName)
	if err != nil {
		return err
	}
	followModel := new(models.WechatFollows)
	ormer := orm.NewOrm()
	ormer.QueryTable(followModel.TableName()).Filter("openid", userinfo.OpenID).One(followModel)

	followModel.FollowsDate = time.Now().Unix()
	followModel.CreatedAt = followModel.FollowsDate
	followModel.UpdatedAt = followModel.FollowsDate
	followModel.NickName = userinfo.Nickname
	followModel.Address = userinfo.Country + "-" + userinfo.City
	if followModel.Id == 0 { //新增
		followModel.Openid = userinfo.OpenID
		followModel.Headimg = userinfo.HeadImgURL
		if userinfo.Sex == 1 {
			followModel.Sex = "男"
		} else {
			followModel.Sex = "女"
		}
		if _, err := ormer.Insert(followModel); err != nil {
			return err
		}
	} else { //更新
		if _, err := ormer.Update(followModel, "headimg", "updated_at", "nick_name"); err != nil {
			return err
		}
	}
	return nil
}

//检测菜单类型
func (s *WechatApiService) checkMenusType(value *models.WechatMenu) *menu.Button {
	btn := new(menu.Button)
	if value.MenuType == 1 { //view
		btn.SetViewButton(value.MenuName, value.MenuContent)
	} else if value.MenuType == 2 { //click
		btn.SetClickButton(value.MenuName, value.MenuContent)
	} else {
		return nil
	}
	return btn
}

//生成自定义菜单
func (s *WechatApiService) CreateMenus(curuser models.BackendUser) error {
	wc := s.NewWechatApiService()
	mu := wc.GetMenu()

	model := models.WechatMenu{}
	menus := model.All(curuser)
	if len(menus) <= 0 {
		return errors.New("没有可用的菜单")
	}
	mainButtons := make([]*menu.Button, 0)
	var mlen = 0
	for _, v := range menus {
		mainBtn := new(menu.Button)
		mlen++
		buttons := make([]*menu.Button, 0)
		if len(v.Childs) > 0 { //子菜单存在
			for _, cv := range v.Childs {
				if value := s.checkMenusType(cv); value != nil {
					buttons = append(buttons, value)
				}
			}
			mainBtn.SetSubButton(v.MenuName, buttons)
			mainButtons = append(mainButtons, mainBtn)
		} else {
			if value := s.checkMenusType(v); value != nil {
				mainButtons = append(mainButtons, value)
			}
		}
		if mlen >= 3 { //主菜单超过三条则不处理
			break
		}
	}
	if err := mu.SetMenu(mainButtons); err != nil {
		return err
	}
	return nil
}

//返回JS-SDK
func (s *WechatApiService) JsSdk(uri string) (*js.Config, error) {
	wc := s.NewWechatApiService()
	js := wc.GetJs()
	cfg, err := js.GetConfig(uri)
	if err != nil {
		return nil, err
	}
	return cfg, nil
}

//获取用户基本信息
func (s *WechatApiService) GetUserInfo(openid message.CDATA) (result *oauth.UserInfo, err error) {
	wc := s.NewWechatApiService()
	oauth := wc.GetOauth()
	accessToken, err := oauth.GetAccessToken()
	if err != nil {
		return nil, err
	}
	var response []byte
	urlStr := fmt.Sprintf(getUserInfo, accessToken, openid)
	response, err = util.HTTPGet(urlStr)
	if err != nil {
		return nil, err
	}
	err = json.Unmarshal(response, &result)
	if result.ErrCode != 0 {
		err = fmt.Errorf("GetUserInfo error : errcode=%v , errmsg=%v", result.ErrCode, result.ErrMsg)
		return
	}
	return
}

//发起授权
func (s *WechatApiService) Oauth(site, scope string, w http.ResponseWriter, r *http.Request) error {
	wc := s.NewWechatApiService()
	oauth := wc.GetOauth()

	err := oauth.Redirect(w, r, site+"/mobile/wx/entry", scope, "weiboxs+")
	if err != nil {
		return err
	}
	return nil
}
